﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TextTemplating;

namespace SharePoint.Orm.Metal.T4 {
	public class CustomDirectiveProcessor : DirectiveProcessor {
		private StringBuilder _codeBuffer;
		private CodeDomProvider _codeDomProvider;
		public static object Parameters { get; set; }

		public override void StartProcessingRun(CodeDomProvider languageProvider, String templateContents, CompilerErrorCollection errors) {
			_codeDomProvider = languageProvider;
			_codeBuffer = new StringBuilder();
		}

		public override bool IsDirectiveSupported(string directiveName) {
			if (string.Equals(directiveName, "contentTypeTemplate", StringComparison.InvariantCultureIgnoreCase)) {
				return true;
			}
			if (string.Equals(directiveName, "listTemplate", StringComparison.InvariantCultureIgnoreCase)) {
				return true;
			}
			return false;
		}

		public override void ProcessDirective(string directiveName, IDictionary<string, string> arguments) {
			if (string.Equals(directiveName, "contentTypeTemplate", StringComparison.InvariantCultureIgnoreCase)) {
				ProcessTemplateDirective();
			} else if (string.Equals(directiveName, "listTemplate", StringComparison.InvariantCultureIgnoreCase)) {
				ProcessTemplateDirective();
			} else {
				throw new Exception("Invalid directive " + directiveName);
			}
		}

		private void ProcessTemplateDirective() {
			CodeGeneratorOptions options = new CodeGeneratorOptions {
				BlankLinesBetweenMembers = true,
				IndentString = "    ",
				VerbatimOrder = true,
				BracingStyle = "C"
			};

			using (StringWriter writer = new StringWriter(_codeBuffer, CultureInfo.InvariantCulture)) {
				CodeTypeReferenceExpression typeReferenceExpression = new CodeTypeReferenceExpression(typeof(CustomDirectiveProcessor));
				CodePropertyReferenceExpression propExpression = new CodePropertyReferenceExpression(typeReferenceExpression, "Parameters");
				CodeCastExpression initExpression = new CodeCastExpression(Parameters.GetType(), propExpression);
				CodeMemberField field = new CodeMemberField {
					Name = "parameters",
					Type = new CodeTypeReference(Parameters.GetType()),
					// ReSharper disable BitwiseOperatorOnEnumWihtoutFlags
					Attributes = MemberAttributes.Public | MemberAttributes.Final,
					// ReSharper restore BitwiseOperatorOnEnumWihtoutFlags
					InitExpression = initExpression
				};

				_codeDomProvider.GenerateCodeFromMember(field, writer, options);
			}
		}

		public override void FinishProcessingRun() {
		}

		public override string GetClassCodeForProcessingRun() {
			return _codeBuffer.ToString();
		}

		public override string GetPreInitializationCodeForProcessingRun() {
			return string.Empty;
		}

		public override string GetPostInitializationCodeForProcessingRun() {
			return string.Empty;
		}

		public override string[] GetReferencesForProcessingRun() {
			return new[] {
				this.GetType().Assembly.Location
			};
		}

		public override string[] GetImportsForProcessingRun() {
			return new string[] { };
		}
	}
}
